﻿namespace Toolkit

open System
open System.Collections.Generic

module Reflection =

    let primitiveTypes = 
        [typeof<byte>
         typeof<sbyte>
         typeof<int16>
         typeof<uint16>
         typeof<int32>
         typeof<uint32>
         typeof<int64>
         typeof<uint64>
         typeof<float32>
         typeof<float>
         typeof<decimal>
         typeof<char>
         typeof<bool>]

    let nullableTypes = 
        [typeof<Nullable<byte>>
         typeof<Nullable<sbyte>>
         typeof<Nullable<int16>>
         typeof<Nullable<uint16>>
         typeof<Nullable<int32>>
         typeof<Nullable<uint32>>
         typeof<Nullable<int64>>
         typeof<Nullable<uint64>>
         typeof<Nullable<float32>>
         typeof<Nullable<float>>
         typeof<Nullable<decimal>>
         typeof<Nullable<char>>
         typeof<Nullable<bool>>
         typeof<Nullable<DateTime>>]

    let stringType = 
        [typeof<string>]

    let dateTimeType = 
        [typeof<DateTime>]

    let isConvertibleType (typ : Type) =  
         primitiveTypes
         |> Seq.append stringType
         |> Seq.append dateTimeType
         |> Seq.exists ((=) typ)

    let (|ConvertibleType|_|) (ty: Type) =
        if not(isConvertibleType ty)
        then None
        else Some(ty)

    let isNullableType (typ : Type) =  
         nullableTypes
         |> Seq.exists (fun t -> t = typ)

    let (|NullableType|_|) (ty: Type) =
        if not(isNullableType ty)
        then None
        else Some(ty)

    let (|DateTimeOffsetType|_|) (ty: Type) =
        if not(ty = typeof<DateTimeOffset>)
        then None
        else Some(ty)

    // For later...
    let (|ArrayType|_|) (ty : Type) = 
        if not(ty.IsArray)
        then None
        else Some(ty.GetElementType(), ty.GetArrayRank())